package world3d.world.entities;

import com.sun.scenario.effect.impl.BufferUtil;
import world3d.world.Entity;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import java.nio.FloatBuffer;
import java.util.Random;

public class GalaxyEntity extends Entity {

	float[] pointsData;
	float[] pointsDataSpeed;
	double[] pointsDataMasa;
	FloatBuffer colors;
	float[] colorsData;
	final int nbPoints = 1000;
	FloatBuffer points;
	Random random = new Random();
	private int size;

	private int nbValues;
	@Override
	public void display() {
		movePoints();
		draw(size, nbValues);
		gl2.glDrawArrays( GL.GL_POINTS, 0, nbPoints );
	}

	@Override
	public void init(GLAutoDrawable glAutoDrawable) {
		super.init(glAutoDrawable);
		gl2.glEnableClientState( GL2.GL_VERTEX_ARRAY );
		gl2.glEnableClientState( GL2.GL_COLOR_ARRAY );
		initArrayData();
	}

	private void movePoints() {
		for (int i = 0; i<pointsData.length-1; i++) {
			int startIndex;
			if(i==0){
				startIndex = 0;
			} else if(i==1){
				startIndex = 1;
			} else if(i==2){
				startIndex = 2;
			} else if(i%2==0){
				startIndex = 2;
			} else if((i+1)%2 == 0 ){
				startIndex = 1;
			} else {
				startIndex = 0;
			}
			for (int j = startIndex; j < pointsData.length - 1; j += 3) {

				float distance = Math.abs(pointsData[j] - pointsData[i]);
				int vector = pointsData[j] - pointsData[i]<0?-1:1;
				double gravitation = pointsDataMasa[j] / pointsDataMasa[i];
				if(Double.isInfinite(pointsData[j]) || Double.isInfinite(gravitation) || Double.isInfinite(pointsDataSpeed[i] + gravitation*vector)){
					pointsDataSpeed[i] += 1;
					System.out.println("isInfinite");
				} else {
					pointsDataSpeed[i] += gravitation*vector*.0001;
				}
			}
			int i1 = 1000;
			if(Double.isInfinite(pointsDataSpeed[i]/ i1)){
				System.out.println("isInfinite");
				pointsData[i] += .1;
			} else {
				pointsData[i] += pointsDataSpeed[i] / i1;
			}

		}

	}
	private void initArrayData()
	{
		// Create data points on the surface of a cube.
		size = 3;
		nbValues = nbPoints * size;
		pointsData = new float[nbValues];
		pointsDataSpeed = new float[nbValues];
		pointsDataMasa = new double[nbValues];
		colorsData = new float[nbValues];
		float speedSumX = 0;
		float radius = .3f;
		float speed = 15f;
		float maxMasa = 150000000f;
		for( int i=0; i < nbValues; i++ ) {
			float randomF = random.nextFloat()* radius;

			pointsData[ i ] = randomF;
			pointsDataSpeed[ i ] = 0;
			float newSpeed = random.nextFloat() * speed - speed * .5f + -speedSumX/2;
			if(i==nbValues-1){
				newSpeed = -speedSumX;
			}
			pointsDataSpeed[i] = newSpeed;
			speedSumX+=newSpeed;
			if((i-1)%2==0 && i!=nbValues-1){
				float newMasa = random.nextFloat() * maxMasa + maxMasa * .05f;
				pointsDataMasa[ i ] = newMasa;
				pointsDataMasa[ i - 1] = newMasa;
				pointsDataMasa[ i + 1] = newMasa;
			}

			colorsData[ i ] = random.nextFloat();
		}
		double maxMass = getMax(pointsDataMasa);
		for( int i=0; i < colorsData.length-1; i++ ) {
			colorsData[ i ] = (float) (pointsDataMasa[i]/maxMass);
		}
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		createRandomMassivePoint(radius*random.nextInt(5), maxMasa*5);
		// Points.
		draw(size, nbValues);
	}

	private void createRandomMassivePoint(float radius, float massa) {
		int index;
		index = random.nextInt(pointsDataMasa.length - 1);
		while ((index-1)%2!=0){
			index++;
		}
		pointsDataMasa[index] = massa;
		pointsDataMasa[index-1] = massa;
		pointsDataMasa[index+1] = massa;
		pointsData[index] = radius* getRandomVector();
		pointsData[index-1] = radius * getRandomVector();
		pointsData[index+1] = radius* getRandomVector();
		pointsDataSpeed[index] = 1;
		pointsDataSpeed[index-1] = 1;
		pointsDataSpeed[index+1] = 1;
	}

	private int getRandomVector() {
		return (random.nextBoolean()?1:-1);
	}

	private double getMax(double[] pointsDataMasa) {
		double res = pointsDataMasa[pointsDataMasa.length-1];
		for (double v : pointsDataMasa) {
			if(res<v){
				res = v;
			}
		}

		return res;
	}

	private void draw(int size, int nbValues) {
		points = BufferUtil.newFloatBuffer(nbValues);
		points.put( pointsData, 0, nbValues );
		points.rewind();
		gl2.glVertexPointer(size, GL2.GL_FLOAT, 0, points);
		// Colors.
		colors = BufferUtil.newFloatBuffer( nbValues );
		colors.put( colorsData, 0, nbValues );
		colors.rewind();
		gl2.glColorPointer(size, GL.GL_FLOAT, 0, colors );
	}

	@Override
	public void reshape(int x, int y, int width, int height) {
		System.out.println("x: " + x + "y: " + y + "width: " + width + "height: " + height);
	}

	@Override
	public void dispose() {

	}
}
